package com.hd.manager.shiro;


import com.hd.appcommon.entity.Privilege;
import com.hd.appcommon.service.IPrivilegeService;
import com.hd.manager.shiro.filter.ShiroFormAuthenticationFilter;
import com.hd.manager.shiro.token.PrivilegeCache;
import com.hd.hdxgddcommon.utils.StringUtils;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.Cookie;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.DependsOn;
import org.springframework.data.redis.core.RedisTemplate;

import javax.servlet.Filter;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * shiro配置  注意 目前不用這個了
 */
//@Configuration
public class ShiroConfiguration {
    @Value("${shiro.cookie.path}")
    private String shiroCookiePath;//shiro cookie 允许的域名
    @Value("${shiro.cookie.sessionId}")
    private String shiroCookieSessionId;//shiro cookie sessionId
    @Value("${shiro.cookie.timeOut}")
    private int shiroCookieTimeOut;//shiro cookie 时限
    @Value("${shiro.session.timeOut}")
    private int shiroSessionTimeOut;//shiro session 时长
    @Value("${shiro.session.validation}")
    private int shiroSessionValidation;//shiro session 扫描间隔


    /**
     * 登录认证realm对象
     *
     * @return
     */
    @Bean
    public MyRealm realm() {
        MyRealm realm = new MyRealm();
        return realm;
    }

    /**
     * redis缓存管理器
     *
     * @param redisTemplate spring boot 默认redis操作模版
     * @return
     */
    @Bean
    public ShiroRedisCacheManager redisCacheManager(RedisTemplate redisTemplate) {
        return new ShiroRedisCacheManager(redisTemplate);
    }

    /**
     * shiro 安全管理器
     *
     * @param realm
     * @param cacheManager
     * @param sessionManager
     * @return
     */
    @Bean
    public SecurityManager securityManager(MyRealm realm, ShiroRedisCacheManager cacheManager, DefaultWebSessionManager sessionManager) {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(realm);
        securityManager.setCacheManager(cacheManager);
        securityManager.setSessionManager(sessionManager);
        return securityManager;
    }

    /**
     * shiro核心过滤器
     *
     * @return
     */
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(IPrivilegeService privilegeService, SecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        Map<String, Filter> filtersMap = new LinkedHashMap<>();
        //自定义权限过滤器
//        filtersMap.put("perms", authorizationFilter);
        filtersMap.put("authc", new ShiroFormAuthenticationFilter());
        shiroFilterFactoryBean.setFilters(filtersMap);
        //路径过滤器
        Map<String, String> filterStringMap = new LinkedHashMap<>();
        //自定义权限
        List<Privilege> privileges = privilegeService.listAllAble();
        //初始化自定义权限缓存
        PrivilegeCache.init(privileges);
        privileges.forEach(p -> {
                    String privilegeUrl = p.getPrivilegeUrl();
                    String privilegeKey = p.getPrivilegeKey();
                    if (StringUtils.isNotBlank(privilegeUrl, privilegeKey)) {
                        filterStringMap.put(checkPrivilegeUrl(privilegeUrl), appendPrivilegeKey(privilegeKey));
                    }
                }
        );
        // -- 基本路径 --
        //登录
        filterStringMap.put("/login/submit", "anon");
        //登出
//        filterStringMap.put("/logout", "anon");
        //上传图片
        filterStringMap.put("/upload/picture", "anon");
        filterStringMap.put("/phLock/push", "anon");
        filterStringMap.put("/testIdc/**", "anon");

        filterStringMap.put("/**", "authc");

        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterStringMap);
        return shiroFilterFactoryBean;
    }

    /**
     * .shiro cookie 配置
     *
     * @return
     */
    @Bean
    public Cookie simpleCookie() {
        //设置SessionIdCookie的属性
        Cookie sessionIdCookie = new SimpleCookie(this.shiroCookieSessionId);
        sessionIdCookie.setHttpOnly(false);
        //允许其他域名访问
        sessionIdCookie.setPath(this.shiroCookiePath);
        //-1表示浏览器关闭时失效此Cookie
        sessionIdCookie.setMaxAge(this.shiroCookieTimeOut);//1天
        return sessionIdCookie;
    }

    /**
     * 会话持久化dao
     *
     * @param redisCacheManager
     * @return
     */
    @Bean
    public EnterpriseCacheSessionDAO sessionDao(ShiroRedisCacheManager redisCacheManager) {
        EnterpriseCacheSessionDAO sessionDao = new EnterpriseCacheSessionDAO();
        // 注入redis缓存管理器
        sessionDao.setCacheManager(redisCacheManager);
        // 注入缓存管理器,实现session由redis控制的另一种方案
        // sessionDao.setRedisUtil(redisUtil);

        return sessionDao;
    }

    /**
     * 会话管理器
     *
     * @param sessionDAO
     * @param sessionIdCookie
     * @return
     */

    @Bean(name = "sessionManager")
    public DefaultWebSessionManager defaultWebSessionManager(EnterpriseCacheSessionDAO sessionDAO,
                                                             Cookie sessionIdCookie) {
        DefaultWebSessionManager sessionManager = new ShiroSessionManager();

        sessionManager.setSessionIdCookie(sessionIdCookie);
        sessionManager.setGlobalSessionTimeout(this.shiroSessionTimeOut);
        //url中是否显示sessionId
        sessionManager.setSessionIdUrlRewritingEnabled(false);
        //删除失效的session
        sessionManager.setDeleteInvalidSessions(true);
        sessionManager.setSessionValidationSchedulerEnabled(true);
        //设置session的失效扫描间隔,单位为毫秒
        sessionManager.setSessionValidationInterval(this.shiroSessionValidation);

        sessionManager.setSessionDAO(sessionDAO);
        return sessionManager;
    }

    /**
     * 加入注解的使用 , 不加入这个注解不生效
     *
     * @param securityManager
     * @return
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }

    /**
     * static最先加载 用于读取配置文件的内容
     *
     * @return
     */
    @Bean
    public static LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }

    @Bean
    @DependsOn("lifecycleBeanPostProcessor")
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
        return defaultAdvisorAutoProxyCreator;
    }

    private String checkPrivilegeUrl(String privilegeUrl) {
        if (!privilegeUrl.startsWith("/"))
            return new StringBuilder("/").append(privilegeUrl).toString();
        return privilegeUrl;
    }

    private String appendPrivilegeKey(String privilegeKey) {
        return new StringBuilder("perms[").append(privilegeKey).append("]").toString();
    }
}